package com.xinqi.modules.prepare.question.service.impl;

import cn.hutool.core.util.StrUtil;
import com.xinqi.common.core.constant.Constants;
import com.xinqi.common.core.enums.CourseExamQuestionEnum;
import com.xinqi.common.base.dto.CommonFileDTO;
import com.xinqi.common.base.dto.QuestionBaseDTO;
import com.xinqi.common.base.dto.QuestionOptionsDTO;
import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.modules.prepare.common.constant.PrepareConstant;
import com.xinqi.modules.prepare.common.utils.AliYunOssUtil;
import com.xinqi.modules.prepare.prepare.enums.PrepareQuestionImportItemTypeEnum;
import com.xinqi.modules.prepare.prepare.enums.PrepareQuestionTypeEnum;
import com.xinqi.modules.prepare.question.service.PrepareQuestionImportService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPicture;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

;

/**
 * @author: wenjie
 * @date: 2023/3/26 10:53
 */
@Validated
@Service("prepareQuestionImportService")
@RequiredArgsConstructor
public class PrepareQuestionImportServiceImpl implements PrepareQuestionImportService {
    @Override
    public List<QuestionBaseDTO> docxToWordImportQuestions(MultipartFile file) throws Exception {
        String fileName = file.getOriginalFilename();
        assert fileName != null;
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        CommonErrors.BAD_REQUEST.check(Objects.equals(Constants.DOCX_DROP_SUF, fileType), "仅支持 .docx 格式的文件导入解析");
        List<QuestionBaseDTO> questionList;
        try {
            questionList = getQuestionList(new XWPFDocument(file.getInputStream()).getParagraphs());
            CommonErrors.BAD_REQUEST.check(CollectionUtils.isNotEmpty(questionList), "请参照文档示例编辑word试题");
        } catch (Exception e) {
            throw new Exception("请参照文档示例编辑word试题");
        }
        return questionList;
    }

    /**
     * 获取question对象集
     *
     * @param source
     * @return
     */
    @Override
    public List<QuestionBaseDTO> getQuestionList(List<XWPFParagraph> source) throws URISyntaxException {
        List<QuestionBaseDTO> questionList = new ArrayList<>();
        List<Integer> separatorList = this.getSeparatorIndexList(source, PrepareConstant.PrepareWordImportConstant.REGEX);
        //分隔题型
        Map<String, List<XWPFParagraph>> listMap = this.getTypeSeparatorMapList(source, separatorList);
        for (Map.Entry<String, List<XWPFParagraph>> entries : listMap.entrySet()) {
            String type = entries.getKey();

            //分割题型中的每个题目
            List<Integer> questionSeparatorList = this.getSeparatorIndexList(entries.getValue(), PrepareQuestionImportItemTypeEnum.FINISH.getDescribe());
            Map<Integer, List<XWPFParagraph>> questionlistMap = this.getQuestionSeparatorMapList(entries.getValue(), questionSeparatorList);

            //每个题型里面分题目
            for (Map.Entry<Integer, List<XWPFParagraph>> questionEntries : questionlistMap.entrySet()) {

                //一个题目
                QuestionBaseDTO question = new QuestionBaseDTO();
                question.setType(type);
                question.setQuestion(PrepareQuestionTypeEnum.getDescribe(type));
                question.setOptionList(new ArrayList<>());
                questionList.add(question);

                //每个题目里面的属性
                for (XWPFParagraph paragraph : questionEntries.getValue()) {
                    //解析paragraph，设置question属性
                    this.setProperties(question, paragraph);
                }
            }

        }

        this.setQuestionSort(questionList);
        return questionList;
    }

    private void setProperties(QuestionBaseDTO question, XWPFParagraph paragraph) throws URISyntaxException {
        String text = paragraph.getParagraphText();
        if (StringUtils.isNotEmpty(text)) {
            if (text.contains(PrepareQuestionImportItemTypeEnum.TOPIC.getDescribe())) {
                Pattern pattern = Pattern.compile(PrepareConstant.PrepareWordImportConstant.SCORE_REGEX);
                //提取分数
                BigDecimal score = extractScore(text, pattern);
                question.setScore(score);

                //去除题目标签
                String topic = this.subListLabel(text, PrepareConstant.PrepareWordImportConstant.LABEL_REGEX);
                //去除题号
                String content = this.subListLabel(topic, StrUtil.DOT);
                question.setContent(content);

                List<CommonFileDTO> contentPictureList = this.getPictures(paragraph);
                if (CollectionUtils.isNotEmpty(contentPictureList)) {
                    question.setQuestionFiles(contentPictureList);
                }
            } else if (text.contains(PrepareQuestionImportItemTypeEnum.ANSWER.getDescribe())) {

                String answer = this.subListLabel(text, PrepareConstant.PrepareWordImportConstant.LABEL_REGEX);
                if (Objects.equals(String.valueOf(CourseExamQuestionEnum.FILL_IN_BLANK.getCode()),
                        question.getType()) && StringUtils.isNotEmpty(question.getAnswer())) {
                    answer = question.getAnswer() + "\n" + answer;
                }

                question.setAnswer(answer);
                List<CommonFileDTO> answerPictureList = this.getPictures(paragraph);
                if (CollectionUtils.isNotEmpty(answerPictureList)) {
                    question.setAnswerFiles(answerPictureList);
                }
            } else if (text.contains(PrepareQuestionImportItemTypeEnum.CHOICE.getDescribe())) {
                //针对选项做拆分
                this.getOptions(paragraph, question);
            } else if (text.contains(PrepareQuestionImportItemTypeEnum.ANALYSIS.getDescribe())) {

                String analysis = this.subListLabel(text, PrepareConstant.PrepareWordImportConstant.LABEL_REGEX);
                question.setAnalysis(analysis);

                List<CommonFileDTO> analysisPictureList = this.getPictures(paragraph);
                if (CollectionUtils.isNotEmpty(analysisPictureList)) {
                    question.setAnalysisFiles(analysisPictureList);
                }
            }
        }
    }

    /**
     * 截掉内容中的标签 】2.出台中央八项规定，
     * 截取之后：2.出台中央八项规定
     *
     * @param text
     * @return
     */
    private String subListLabel(String text, String label) {
        int index = text.indexOf(label);
        if (index > -1) {
            text = text.substring(index + 1);
        }
        return text;
    }

    /**
     * 设置题目顺序
     *
     * @param list
     */
    private void setQuestionSort(List<QuestionBaseDTO> list) {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setSort(i + 1);
        }
    }

    /**
     * 设置图片
     *
     * @param paragraph
     * @return
     */
    private List<CommonFileDTO> getPictures(XWPFParagraph paragraph) {

        List<CommonFileDTO> contentFiles = new ArrayList<>();
        List<XWPFPicture> questionPictures = new ArrayList<>();

        List<XWPFRun> runs = paragraph.getRuns();
        if (CollectionUtils.isNotEmpty(runs)) {
            for (XWPFRun run : runs) {
                List<XWPFPicture> pictures = run.getEmbeddedPictures();
                if (CollectionUtils.isNotEmpty(pictures)) {
                    questionPictures.addAll(pictures);
                }
            }
        }

        //图片上传需要公共的上传文件支持
        if (CollectionUtils.isNotEmpty(questionPictures)) {
            for (XWPFPicture p : questionPictures) {
                contentFiles.add(uploadAndSetProps(p));
            }
        }

        return contentFiles;

    }

    private CommonFileDTO uploadAndSetProps(XWPFPicture p) {
        //将图片上传到阿里云,并封装成 FileInsertBean 对象
        return AliYunOssUtil.uploadFileStream(p.getDescription(), 2, new ByteArrayInputStream(p.getPictureData().getData()));
    }

    /**
     * 获取选项
     *
     * @param paragraph
     * @return
     */
    private void getOptions(XWPFParagraph paragraph, QuestionBaseDTO question) throws URISyntaxException {
        List<QuestionOptionsDTO> optionInits = question.getOptionList();
        String text = paragraph.getParagraphText();
        //【选项】A.形式主义
        String options = this.subListLabel(text, PrepareConstant.PrepareWordImportConstant.LABEL_REGEX);

        int index = options.indexOf(StrUtil.DOT);
        if (index > -1) {
            QuestionOptionsDTO option = new QuestionOptionsDTO();

            String key = options.substring(0, index).trim();
            String value = options.substring(index + 1);
            option.setId(key);
            option.setVal(value);

            if (question.getAnswer().contains(StrUtil.COMMA)) {
                List<String> answers = new ArrayList<>(Arrays.asList(question.getAnswer().split(StrUtil.COMMA)));
                if (answers.contains(key)) {
                    option.setSelected(YesNoEnum.YES.ordinal());
                } else {
                    option.setSelected(YesNoEnum.NO.ordinal());
                }
            } else {
                if (Objects.equals(question.getAnswer().trim(), key)) {
                    option.setSelected(YesNoEnum.YES.ordinal());
                } else {
                    option.setSelected(YesNoEnum.NO.ordinal());
                }
            }

            optionInits.add(option);

            //设置选项上的图片
            this.setPictures(paragraph, option);

        }
    }

    //设置选项上的图片
    private void setPictures(XWPFParagraph paragraph, QuestionOptionsDTO option) {
        List<CommonFileDTO> optionFiles = this.getPictures(paragraph);
        if (CollectionUtils.isNotEmpty(optionFiles)) {
            option.setFileUrls(optionFiles);
        }

    }

    /**
     * 注意：从[2分]中提取分值
     *
     * @param content
     * @return
     */

    private BigDecimal extractScore(String content, Pattern pattern) {
        if (content.contains(StrUtil.BRACKET_START) && content.contains(StrUtil.BRACKET_END)) {

            String left = content.substring(content.lastIndexOf(StrUtil.BRACKET_START));
            String scoreText = left.substring(0, left.lastIndexOf(StrUtil.BRACKET_END));

            Matcher m = pattern.matcher(scoreText);
            String scoreValue = m.replaceAll("").trim();

            if (StringUtils.isNotEmpty(scoreValue)) {
                return BigDecimal.valueOf(Integer.parseInt(scoreValue));
            }
        }
        return null;
    }


    /**
     * 分隔符是变化的，根据分隔符，返回一组下标。
     *
     * @param source
     * @param reg
     * @return
     */
    public List<Integer> getSeparatorIndexList(List<XWPFParagraph> source, String reg) {
        List<Integer> separatorList = new ArrayList<>();
        Pattern compile = Pattern.compile(reg);
        if (CollectionUtils.isNotEmpty(source)) {
            for (int i = 0; i < source.size(); i++) {
                if (compile.matcher(source.get(i).getParagraphText()).find()) {
                    separatorList.add(i);
                }
            }
        }
        return separatorList;
    }

    /**
     * 根据下标将题型分开
     *
     * @param separatorList
     * @param source
     * @return
     */
    public Map<String, List<XWPFParagraph>> getTypeSeparatorMapList(List<XWPFParagraph> source, List<Integer> separatorList) {
        Map<String, List<XWPFParagraph>> mapList = new HashMap<>();
        //用来标记分隔符的下标
        int separatorIndex = 0;
        //list子数组的开始位置
        int start;
        //list子数组的结束位置
        int end;
        for (int i = 0; i < separatorList.size(); i++) {
            start = separatorList.get(separatorIndex);
            if (separatorIndex < separatorList.size() - 1) {
                end = separatorList.get(++separatorIndex);
            } else {
                end = source.size();
            }
            List<XWPFParagraph> subList = new ArrayList<>(source.subList(start + 1, end));
            String text = source.get(start).getParagraphText();
            String key = PrepareQuestionTypeEnum.getCode(text);
            mapList.put(key, subList);
        }

        return mapList;
    }


    public Map<Integer, List<XWPFParagraph>> getQuestionSeparatorMapList(List<XWPFParagraph> source, List<Integer> questionSeparatorList) {
        Map<Integer, List<XWPFParagraph>> mapList = new HashMap<>();
        //用来标记分隔符的下标
        //list子数组的开始位置
        int start;
        //list子数组的结束位置
        int end;
        for (int i = 0; i < questionSeparatorList.size(); i++) {
            //开始位置为结束位置的下一行开始
            if (i == 0) {
                start = 0;
            } else {
                //不包含结束符
                start = questionSeparatorList.get(i - 1) + 1;
            }
            end = questionSeparatorList.get(i);

            List<XWPFParagraph> subList = new ArrayList<>(source.subList(start, end));
            //i代表题号
            mapList.put(i + 1, subList);
        }

        return mapList;
    }
}
